#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>

#include "utils.h"

// 使用静态库，需要定义 PCRE2_STATIC，否则会出现“无法解析的外部符号 __imp_pcre2_compile_8”错误！
//#define PCRE2_STATIC
// PCRE2_CODE_UNIT_WIDTH must be defined before including pcre2.h
#define PCRE2_CODE_UNIT_WIDTH 8

#include "pcre2.h"

#include "pcre2_regexp.h"

#include "log.h"
#define LOGLEVEL LOG_DEBUG
#define LOGTAG   "REGEXP"
#include "log4app.h"

// 正则表达式缓存
// 上一次匹配的模式，如果再次匹配相同的模式可以使用编译过的表达式
static struct _regexp_cache {
    char pattern[128];  // 正则表达式
    pcre2_code* code;   // 编译过的表达式
    size_t hit;         // 命中次数
} _cache[REGEXP_CACHE_MAX] = {0};

void regexp_cache_init() {
    memset(_cache, 0, sizeof(_cache));
}

void regexp_cache_clear() {
    for (int i = 0; i < REGEXP_CACHE_MAX; i++) {
        if (_cache[i].code) pcre2_code_free(_cache[i].code);
    }
    regexp_cache_init();
}

/**
* 在正则表达式缓存中查找指定表达式，如果没找到，就编译并缓存指定表达式
* @param pattern 正则表达式
* @return 编译过的正则表达式代码指针。返回 NULL 表示正则表达式中有错误。
*/
static pcre2_code* regexp_cache_compile(const char* pattern) {
    for (int i = 0; i < REGEXP_CACHE_MAX; i++) {
        // 如果模式相同，则返回编译好的代码
        if (_cache[i].code && strcmp(_cache[i].pattern, pattern) == 0) {
            _cache[i].hit++;
            return _cache[i].code;
        }
    }

    // 是未缓存的正则表达式
    // 查找未使用的位置或命中次数最少的表达式
    int idx = -1;
    size_t hit = SIZE_MAX;
    for (int i = 0; i < REGEXP_CACHE_MAX; i++) {
        // 如果是未使用的位置，则直接返回
        if (_cache[i].code == NULL) { idx = i; break; }
        // 找到命中次数最少的表达式
        if (_cache[i].hit < hit) idx = i;
    }
    struct _regexp_cache* cache = &_cache[idx];

    // 释放原有的表达式
    if (cache->code) { pcre2_code_free(cache->code); cache->code = NULL; cache->hit = 0; }

    // 编译正则表达式
    int error_code;
    PCRE2_SIZE error_offset;
    cache->code = pcre2_compile((PCRE2_SPTR8)pattern, PCRE2_ZERO_TERMINATED, 0, &error_code, &error_offset, NULL);
    if (cache->code == NULL) {
        PCRE2_UCHAR buffer[256];
        pcre2_get_error_message(error_code, buffer, sizeof(buffer));
        loge("PCRE2 compilation failed at offset %d: %s\n", (int)error_offset, buffer);
        return NULL;
    }
    strncpy(cache->pattern, pattern, sizeof(cache->pattern));

    return cache->code;
}

int regexp_match(const char* str, const char* pattern) {
    // 在正则表达式缓存中查找指定表达式，如果没找到，就编译并缓存指定表达式
    pcre2_code *code = regexp_cache_compile(pattern);
    if (!code) return -1;

    // 匹配的起始位置
    int ps = -1;
    // 匹配正则表达式
    pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(code, NULL);
    // 匹配 pcre 编译好的模式，成功返回正数，失败返回负数
    int ret = pcre2_match(code, (PCRE2_SPTR8)str, PCRE2_ZERO_TERMINATED, 0, 0, match_data, NULL);
    if (ret < 0) goto _final;

    // 输出匹配结果
    ps = (int)pcre2_get_startchar(match_data);
    //logd("%d matches: %s\n", ret, str + ps);

_final:
    // 释放内存
    pcre2_match_data_free(match_data);
    return ps;
}

regexp_capture_result_t regexp_capture(const char* str, size_t startoffset, const char* pattern) {
    // 在正则表达式缓存中查找指定表达式，如果没找到，就编译并缓存指定表达式
    pcre2_code *code = regexp_cache_compile(pattern);
    if (!code) return NULL;

    // 匹配正则表达式
    pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(code, NULL);
    // 匹配 pcre 编译好的模式，成功返回匹配的数量，失败返回负数
    int ret = pcre2_match(code, (PCRE2_SPTR8)str, PCRE2_ZERO_TERMINATED, startoffset, 0, match_data, NULL);
    if (ret <= 0) {
        // 释放内存
        pcre2_match_data_free(match_data);
        return NULL;
    }

    return match_data;
}

const char* regexp_get_capture(const char* str, regexp_capture_result_t result, unsigned int idx) {
    if (!result) return NULL;
    pcre2_match_data* match_data = (pcre2_match_data*)result;
    // 判断是否有此匹配
    if (idx >= pcre2_get_ovector_count(match_data)) return NULL;
    // 获取匹配指示数组
    PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(match_data);
    // 匹配字符串起始位置
    const char *ss = str + ovector[2*idx];
    // 匹配字符串长度
    size_t slen = ovector[2*idx+1] - ovector[2*idx];
    // 注意：返回的字符串使用的是局部 static 缓冲区
    static char substr[REGEXP_CAPTURE_MAX];
    slen = min(REGEXP_CAPTURE_MAX - 1, slen);
    // 把匹配的字符串拷贝到一个缓冲区（末尾加 '\0'）
    strncpy(substr, ss, slen); substr[slen] = '\0';
    return substr;
}

void regexp_release_capture(regexp_capture_result_t result) {
    if (result) pcre2_match_data_free(result);
}

const char* regexp_capture1(const char* str, size_t offset, const char* pattern) {
    regexp_capture_result_t result = regexp_capture(str, offset, pattern);
    if (!result) return NULL;
    str = regexp_get_capture(str, result, 1);
    regexp_release_capture(result);
    return str;
}


#if 0
// for test only
int main(int argc, char** argv) {
    _logger = logger_get(NULL);
    logger_add_stdout(_logger);
    const char str[] = "{\"fpga\":3351,\"pa\":4832}";
    regexp_capture_result_t result = regexp_capture(str, 0, "\"fpga\":(\\d+)");
    if (result) {
        logd("full_match: %s\r\n", regexp_get_capture(str, result, 0));
        logd("sub_match: %s\r\n", regexp_get_capture(str, result, 1));
        regexp_release_capture(result);
    }
    return 0;
}
#endif
